from dc_shop.core.models.dto import PaymentDetailsDTO
from dc_shop.core.models.dto.cart import CartLineDTO
from dc_shop.core.models.dto.order import OrderLineDTO
from dc_shop.core.models.enums.currency import Currency, CurrencySymbol
from dc_shop.core.models.enums.product import MeasurementUnit
from dc_shop.core.utils.currency import convert_currency, get_currency_rate
from dc_shop.database.services import DiscountService, ProductService


def calculate_product_discount(product_price: float, discount_percent: float):
    """Рассчитываем скидку на товар"""

    discounted_price = product_price - (product_price * discount_percent / 100)

    return discounted_price


def format_cart_line(
    product_title: str,
    product_total: float,
    measurement: MeasurementUnit,
    quantity: int,
    currency_symbol: str = "฿",
):
    """Форматируем строку с товаром в корзине"""

    measurement_unit = "gr."
    if measurement == MeasurementUnit.pcs:
        measurement_unit = "pcs."
    return f"- {product_title} ({quantity} {measurement_unit}) – {product_total} {currency_symbol}\n"


async def calculate_total_summ(
    items: list[CartLineDTO | OrderLineDTO],
    shop_id: int,
    payment_method: PaymentDetailsDTO,
    product_service: ProductService,
    discount_service: DiscountService,
    promocode_value: float | None = None,
) -> float:
    """Рассчитываем сумму заказа / корзины с учетом валюты, скидок и промокода"""

    order_summ = 0
    exchange_rate = get_currency_rate(payment_method.currency)
    if not exchange_rate:
        raise ValueError(f"Не удалось получить курс валюты {payment_method.currency}")

    # Получаем список товаров
    products = [await product_service.get_product_by_id(item.product_id) for item in items]
    for item in items:
        product = await product_service.get_product_by_id(item.product_id)
        product_price = product.price

        # Получаем количество товаров из той же категории в корзине / заказе
        category_products_ids = [p.id for p in products if p.category_id == product.category_id]
        category_products_quantity = sum(
            product.quantity for product in items if product.product_id in category_products_ids
        )

        if payment_method.currency not in [Currency.thb, Currency.cash]:
            # Рассчитываем цену для заказов не в батах
            product_price = convert_currency(product_price, exchange_rate, payment_method.exchange_percent)

        # Рассчитываем максимальную скидку по товару
        discount = await discount_service.get_discount_by_category_and_shop(
            product.category_id, shop_id, category_products_quantity
        )
        if discount and not discount.works_inside_category:
            # Получаем скидку по product_count, если скидка не распространяется на категорию
            discount = await discount_service.get_discount_by_category_and_shop(
                product.category_id, shop_id, item.quantity
            )
        discounted_price = (
            calculate_product_discount(product_price, discount.discount_percent) if discount else product_price
        )

        if promocode_value:
            discounted_price -= product_price * (promocode_value / 100)

        product_total = round(discounted_price * item.quantity, 8 if payment_method.currency == Currency.btc else 2)

        order_summ += product_total

    return round(order_summ, 8 if payment_method.currency == Currency.btc else 2)


async def generate_product_lines(
    items: list[CartLineDTO | OrderLineDTO],
    shop_id: int,
    payment_method: PaymentDetailsDTO,
    product_service: ProductService,
    discount_service: DiscountService,
    promocode_value: float | None = None,
):
    """Генерируем текст с информацией о количестве и цене товаров"""

    txt = ""
    exchange_rate = get_currency_rate(payment_method.currency)
    if not exchange_rate:
        raise ValueError(f"Не удалось получить курс валюты {payment_method.currency}")

    # Получаем список товаров
    products = [await product_service.get_product_by_id(item.product_id) for item in items]
    for item in items:
        product = await product_service.get_product_by_id(item.product_id)
        product_price = product.price

        # Получаем количество товаров из той же категории в корзине / заказе
        category_products_ids = [p.id for p in products if p.category_id == product.category_id]
        category_products_quantity = sum(
            product.quantity for product in items if product.product_id in category_products_ids
        )

        if payment_method.currency_symbol != CurrencySymbol.thb:
            product_price = convert_currency(
                product_price,
                exchange_rate,
                payment_method.exchange_percent,
            )

        # Рассчитываем максимальную скидку по товару
        discount = await discount_service.get_discount_by_category_and_shop(
            product.category_id, shop_id, category_products_quantity
        )
        if discount and not discount.works_inside_category:
            # Получаем скидку по product_count, если скидка не распространяется на категорию
            discount = await discount_service.get_discount_by_category_and_shop(
                product.category_id, shop_id, item.quantity
            )

        discounted_price = (
            calculate_product_discount(product_price, discount.discount_percent) if discount else product_price
        )

        if promocode_value:
            discounted_price -= product_price * (promocode_value / 100)

        product_total = round(discounted_price * item.quantity, 8 if payment_method.currency == Currency.btc else 2)

        txt += format_cart_line(
            product_title=product.title,
            product_total=product_total,
            measurement=product.measurement,
            quantity=item.quantity,
            currency_symbol=payment_method.currency_symbol.value,
        )

    return txt
